package com.me.libgdx_test;

import java.io.File;
import java.util.ArrayList;
import java.util.Random;
import java.util.concurrent.CopyOnWriteArrayList;

import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.scenes.scene2d.Stage;

public class ClassDungeonPlaceElement {
	private ClassLogDisplay logger;
	private ClassStringArray[][] board;
	private int[][] dungeon;
	private Point game_dimensions,next_move,off_step,test_point, screen_size;
	private String wall,dirt,player_image,steps, cursor,shroud_whole;
	private String path;
	private boolean ready_to_move,just_moved;
	private int steps_to_move;
	private ClassCharacterPlayer player;
	private ClassPlaceObjects objects;
	private CopyOnWriteArrayList<ClassAnimationIterator> animations;
	private CopyOnWriteArrayList<ClassAnimationString> animation_text;
	private ClassAnimationTextureLoader animation_loader;
	private boolean animation_residue;
	ClassPermanentUpgrades perm_upgrades;
	private Random random = new Random(System.currentTimeMillis());
	private ArrayList<Integer> used_messages = new ArrayList<Integer>();
	private ClassReferenceDrawable game_vars;
	private Stage game_stage;
	private ClassSkinReference skin;
	private ClassDialogBox dialog;
	private boolean viable;
	
	//This class creates the map objects before sending them back to the refined asset holder to be drawn
	ClassDungeonPlaceElement(Point game_dimensions, String path, ClassReferenceDrawable game_vars, 
			ClassAnimationTextureLoader animation_loader, Point screen_size, Stage game_stage, ClassSkinReference skin){
		this.game_dimensions = new Point(game_dimensions);
		this.path = path;
		this.animation_loader = animation_loader;
		logger = new ClassLogDisplay("ClassDungeonObjects");
		ClassCreateDungeon base_dungeon = new ClassCreateDungeon(game_dimensions, game_vars.player_level==0?true:false);
		//player = new ClassCharacterPlayer(10,100,1,game_vars.classObjects[game_vars.player_class]);
		perm_upgrades = new ClassPermanentUpgrades(game_vars.shopObjects);
		player = new ClassCharacterPlayer(game_vars.classObjects[game_vars.player_class],
				new ClassCharacterRace(game_vars.raceObjects[game_vars.player_race]),
				game_vars.spellObjects,perm_upgrades);
		animations = new CopyOnWriteArrayList<ClassAnimationIterator>();
		animation_text = new CopyOnWriteArrayList<ClassAnimationString>();
		this.screen_size = screen_size;
		player.set_location(base_dungeon.getPlayer());
		player.init_mods(game_vars.modObjects);
		//player_point = new Point(base_dungeon.getPlayer());
		dungeon = base_dungeon.getMap();
		objects = new ClassPlaceObjects(game_vars, dungeon, player,perm_upgrades);
		wall = path + game_vars.levelObjects[game_vars.player_level].Image;
		dirt = path + game_vars.levelObjects[game_vars.player_level].Second_Image;
		steps = path + "icon_footsteps.png";
		cursor = path + "icon_movement_selector.png";
		shroud_whole = path + "icon_dark_full.png";
		//shroud_whole = path + "icon_dark_half.png";
		player_image = path + game_vars.classObjects[game_vars.player_class].Image;
		board = new ClassStringArray[game_dimensions.x][game_dimensions.y];
		ready_to_move = false;
		just_moved = false;
		next_move = new Point();
		off_step = new Point();
		test_point = new Point();
		steps_to_move = 0;
		this.game_vars = game_vars;
		this.game_stage = game_stage;
		this.skin = skin;
		viable = false;
		create_board();
	}
	public void create_board(){
		//Remember that rendering sprites is much more costly than the calculations required not to render them
		
		//Check for shroud here
		check_shroud();
		
		for (int y = 0; y < game_dimensions.y; y++){
			for (int x = 0; x < game_dimensions.x; x++){
				board[x][y] = new ClassStringArray();
				//test_point.move(x, y);
				//if (!objects.get_shroud().contains(test_point)){
					if(dungeon[x][y]==0){
						board[x][y].string_holder.add(dirt);
					}
					if(dungeon[x][y]==1){
						board[x][y].string_holder.add(wall);
					}
				//}
			}
		}
		for (ClassCharacterEnemy enemy: objects.get_enemies()){
			//logger.print(enemy.get_location());
			//test_point.move(enemy.get_location().x, enemy.get_location().y);
			//if (!objects.get_shroud().contains(test_point)){
				board[enemy.get_location().x][enemy.get_location().y].string_holder.add(path +enemy.enemy_info.Image);
				if(!player.get_attack_mod("Static") && !player.get_contracted_mod("Static")){
					board[enemy.get_location().x][enemy.get_location().y].string_holder.add(path + enemy.level_image +".png");
				}
			//}
		}
		for (ClassObjectPickupDungeon pickup: objects.get_pickups()){
			//logger.print(pickup.get_location());
			//test_point.move(pickup.get_location().x, pickup.get_location().y);
			//if (!objects.get_shroud().contains(test_point)){
			board[pickup.get_location().x][pickup.get_location().y].string_holder.add(path +pickup.get_pickup_info().Image);
			//}
		}
		for (ClassObjectShopDungeon shop: objects.get_shops()){
			//test_point.move(shop.get_location().x, shop.get_location().y);
			//if (!objects.get_shroud().contains(test_point)){
			board[shop.get_location().x][shop.get_location().y].string_holder.add(path +shop.get_shop_image());
			//}
		}
		for (ClassObjectTotem totem: objects.get_totems()){
			board[totem.get_location().x][totem.get_location().y].string_holder.add(path +totem.get_totem_info().Image);
		}
		for (ClassObjectSpellDungeon spell: objects.get_spells()){
			//test_point.move(shop.get_location().x, shop.get_location().y);
			//if (!objects.get_shroud().contains(test_point)){
			board[spell.get_location().x][spell.get_location().y].string_holder.add(path +spell.get_spell_info().Image);
			//}
		}
		for (ClassObjectGodDungeon god: objects.get_gods()){
			//test_point.move(shop.get_location().x, shop.get_location().y);
			//if (!objects.get_shroud().contains(test_point)){
			board[god.get_location().x][god.get_location().y].string_holder.add(path +god.get_altar_image());
			//}
		}
		if(ready_to_move){
			//return_composite_replaced_map
			//ClassShortestPath path = new ClassShortestPath(objects.return_composite_map(),objects.return_placed_map(), player.get_location(), next_move, game_dimensions);
			ClassShortestPath path = new ClassShortestPath(objects.return_shroud_map(),objects.return_composite_replaced_map(), 
					player.get_location(), next_move, game_dimensions);
			ArrayList<Point> path_guide = new ArrayList<Point>(path.returnPath());
			Point cursor_holder = new Point();
			steps_to_move = path_guide.size();
			//logger.print("Steps: " + steps_to_move);
			if(path_guide.size()>1){
				off_step = null;
				for(int i = path_guide.size()-1; i > -1;i--){
					if (i == path_guide.size() -1){
						board[path_guide.get(i).x][path_guide.get(i).y].string_holder.add(cursor);
						cursor_holder.move(path_guide.get(i).x,path_guide.get(i).y);
					}
					else if(i!=0){
						if(cursor_holder.next_to(path_guide.get(i))){
							off_step = path_guide.get(i);
						}
						board[path_guide.get(i).x][path_guide.get(i).y].string_holder.add(steps);
					}
				}
			}else{
				set_ready_to_move(false);
			}
		}
		logger.print("Player Location");
		logger.print(player.location);
		board[player.get_location().x][player.get_location().y].string_holder.add(player_image);
		
		animation_residue = false;
		//player.get_player_animations().clear();
		for(ClassAnimationIterator animation : animations){
			if(!animation.animation_moving()){
				board[animation.get_location().x][animation.get_location().y].string_holder.add(animation.get_frame());
				//This is why animation must be a CopyOnWriteArrayList
				if(animation.animation_over()){
					animations.remove(animation);
					animation_residue = true;
				}
			}
		}
		
		ArrayList<ClassSpriteLocation> shroud_sprites = player.get_class_mods().playerShroudMod.set_see_through_shroud(player, objects);
		
		//Add shroud
		for (Point shroud: objects.get_shroud()){
			board[shroud.x][shroud.y].string_holder.add(shroud_whole);
			//Now we have to check if the player gets hints on where things are
			for(ClassSpriteLocation hint: shroud_sprites){
				if(hint.location.equals(shroud)){
					board[shroud.x][shroud.y].string_holder.add(hint.sprite);
					//There can never be more than one hint per tile...
					break;
				}
			}
		}
	}
	public void check_shroud(){
		int shroud_removed=0;
		Point shroud_check = new Point();
		for(int y = (player.get_location().y-player.get_player_variable("vision"));y<(player.get_location().y+player.get_player_variable("vision")+1);y++){
			for(int x = (player.get_location().x-player.get_player_variable("vision"));x<(player.get_location().x+player.get_player_variable("vision")+1);x++){
				shroud_check.move(x, y);
				//get_shroud
				if (objects.get_shroud().contains(shroud_check)){
					shroud_removed++;
					objects.remove_shroud(shroud_check);
				}
			}
		}
		if(shroud_removed>0){
			for(ClassCharacterEnemy enemy:objects.get_enemies()){
				enemy.refresh_shroud(shroud_removed);
			}
			player.refresh_shroud(shroud_removed,objects);
		}
	}
	public void push_touch(Point touch){
		
		ClassLogDisplay.print("Ready to move: " + String.valueOf(ready_to_move));			
		//ClassLogDisplay.print(next_move.equals(touch));
		ClassLogDisplay.print("Next Move: ");
		ClassLogDisplay.print(next_move);
		ClassLogDisplay.print("Touch: ");
		ClassLogDisplay.print(touch);
		
		if(viable){
			dialog.get_dialog().remove();
			viable = false;
		}
		
		if (ready_to_move && next_move.equals(touch)){
			if(!(objects.return_composite_map()[touch.x][touch.y] == 1)){
			logger.print("No Wall");
			logger.print("Touch");
			logger.print(touch);
			//logger.print("Clicked Twice");
			
			//Are there enemies where the player is moving?
			//ClassCharacterEnemy enemy = is_enemy_there(touch);
			//Are there pickups where the player is moving?
			//ClassObjectPickupDungeon pickup = is_pickup_there(touch);

			ClassCursorAt cursor = is_something_there(touch);
			
			logger.print("Object type: " + cursor.get_object_type());
			
			/*
			 * 	ClassCharacterEnemy enemy;
			 *	ClassObjectShopDungeon shop;
			 *	ClassObjectPickupDungeon pickup;
			 *	ClassObjectTotem totem;
			 *	ClassObjectSpellDungeon spell;
			 */
			if(!viable){
			switch(cursor.get_object_type()){
				case 1:
					Point damage = player.fight_enemy(cursor.enemy);
					
					if(cursor.enemy.current_health <= 0){
						animations.add(new ClassAnimationIterator(cursor.enemy.location,
								animation_loader.return_animation_by_name("animation_xalt"),ClassAnimationIterator.Constants.ANIMATION_LONG,1));
						set_ready_to_move(false);
						objects.remove_enemy(cursor.enemy);
						move_steps(steps_to_move);
						player.set_location(new Point(touch.x,touch.y));
						player.set_contracted_mod("Banish",false);
						//iconObjects[8] is a blood_pool
						if(!cursor.enemy.enemy_info.Name.equals("Grumpkin")){
							ClassObjectPickupDungeon object_holder = new ClassObjectPickupDungeon(objects.get_game_vars().iconObjects[8]);
							object_holder.set_location(player.location);
							objects.add_pickup(object_holder);
						}
					}else{
						/*animation_text.add(
								new ClassAnimationString(player.get_, Point string_location, 20, 10, Color.RED)
								);*/
						
						animations.add(new ClassAnimationIterator(cursor.enemy.location,
								animation_loader.return_animation_by_name("animation_blood"),ClassAnimationIterator.Constants.ANIMATION_NORMAL,1));
						set_ready_to_move(true);
						logger.print("Touch");
						logger.print(touch);
						next_move.move(touch.x, touch.y);
						logger.print("Off Step");
						if(!player.get_contracted_mod("Banish")){
							if(off_step!=null){
								move_steps(steps_to_move-1);
								player.set_location(new Point(off_step.x,off_step.y));
							}
						}else{
							/*ready_to_move = false;
							ArrayList<Point> nothing_array = objects.nothing_there();
							Random random = new Random(System.currentTimeMillis());
							move_steps(steps_to_move);
							player.set_location(new Point(nothing_array.get(random.nextInt(nothing_array.size()))));
							player.set_contracted_mod("Banish",false);*/
							
							set_ready_to_move(false);
							ArrayList<Point> nothing = get_place_objects().nothing_there();
							for(Point noth:nothing){
								logger.print(noth);
							}
							Point p = nothing.get(random.nextInt(nothing.size()));
							logger.print("Banished");
							logger.print(p);
							player.set_location(p);
							player.set_contracted_mod("Banish",false);
							
						}
						if(cursor.enemy.get_attack_mod("Coward") || cursor.enemy.get_contracted_mod("Coward")){
							if(!player.get_contracted_mod("Chains")){
								ArrayList<Point> nothing_array = objects.nothing_there();
								Random random = new Random(System.currentTimeMillis());
								cursor.enemy.set_location(new Point(nothing_array.get(random.nextInt(nothing_array.size()))));
								cursor.enemy.set_contracted_mod("Coward",false);
							}else{
								player.set_contracted_mod("Chains", false);
								cursor.enemy.set_contracted_mod("Coward",false);
							}
						}
						
					}
					
					animation_text.add(
							new ClassAnimationString(""+damage.x, player.get_location(), 20, 10, Color.GREEN));
					animation_text.add(
							new ClassAnimationString(""+damage.y, cursor.enemy.get_location(), 20, 10, Color.RED));
					
					break;
				//case 2:break;
				case 3:
					set_ready_to_move(false);
					move_steps(steps_to_move);
					player.set_location(new Point(touch.x,touch.y));
					if(cursor.pickup.stepped_on(player)){
						animations.add(new ClassAnimationIterator(new Point(screen_size.x/2,screen_size.y/2), 
								new Point(screen_size.x/2,screen_size.y/8),
								animation_loader.return_animation_by_name(cursor.pickup.get_pickup_info().get_pickup_animation()),ClassAnimationIterator.Constants.ANIMATION_LONG,5));
						//ballrotatered
						if(cursor.pickup.get_pickup_info().Name == "Blood Pool"){
							player.add_god_action("blood_pools");
						}
						objects.remove_pickup(cursor.pickup);
					}
					break;
				//case 4:break;
				case 5:
					set_ready_to_move(false);
					move_steps(steps_to_move);
					player.set_location(new Point(touch.x,touch.y));
					if(cursor.spell.pick_up_spell(player)){
						objects.remove_spell(cursor.spell);
					}
					break;
				default:
					set_ready_to_move(false);
					move_steps(steps_to_move);
					player.set_location(new Point(touch.x,touch.y));
					break;
			}
			}
			if(objects.tutorial_messages){
				int message_index = game_vars.tutorialMessageMap[player.get_location().x][player.get_location().y];
				if(!used_messages.contains(message_index)){
					dialog = new ClassDialogBox(game_stage, "Helpful Hint", game_vars.tutorialMessages[message_index], skin.get_alternate_skin(), false);
					used_messages.add(message_index);
					viable = true;
				}
			}
			}
		}else{
			logger.print("First touch");
			set_ready_to_move(true);
			next_move.move(touch.x, touch.y);
		}
		//}
		create_board();
	}
	
	public void set_ready_to_move(boolean ready_to_move){
		logger.print("Setting ready to move to: " + String.valueOf(ready_to_move));
		this.ready_to_move = ready_to_move;
	}
	
	public void move_steps(int steps_moved){
		player.get_class_mods().playerStepMod.set_step_actions(player,steps_moved);
		steps_to_move=0;
	}
	
	public boolean just_moved(){
		if(!just_moved){
			return false;
		}else{
			just_moved = false;
			return true;
		}
	}
	
	public Point get_current_cursor(){
		if(ready_to_move){
			return next_move;
		}else{
			return player.get_location();
		}
	}
	
	public ClassCharacterEnemy is_enemy_there(Point location){
		for (ClassCharacterEnemy enemy: objects.get_enemies()){
			if(enemy.get_location().equals(location)){
				return enemy;
			}
		}
		return null;
	}
	
	public ClassCursorAt is_something_there(Point location){
		for (ClassCharacterEnemy enemy: objects.get_enemies()){
			if(enemy.get_location().equals(location)){
				return new ClassCursorAt(location,enemy);
			}
		}
		for (ClassObjectShopDungeon shop: objects.get_shops()){
			if(shop.get_location().equals(location)){
				return new ClassCursorAt(location,shop);
			}
		}
		for (ClassObjectPickupDungeon pickup: objects.get_pickups()){
			if(pickup.get_location().equals(location)){
				return new ClassCursorAt(location,pickup);
			}
		}
		for (ClassObjectTotem totem: objects.get_totems()){
			if(totem.get_location().equals(location)){
				return new ClassCursorAt(location,totem);
			}
		}
		for (ClassObjectSpellDungeon spell: objects.get_spells()){
			if(spell.get_location().equals(location)){
				return new ClassCursorAt(location,spell);
			}
		}
		for (ClassObjectGodDungeon god: objects.get_gods()){
			if(god.get_location().equals(location)){
				return new ClassCursorAt(location,god);
			}
		}
		return new ClassCursorAt(location);
	}
	public ClassObjectPickupDungeon is_pickup_there(Point location){
		for (ClassObjectPickupDungeon pickup: objects.get_pickups()){
			if(pickup.get_location().equals(location)){
				return pickup;
			}
		}
		return null;
	}
	public ClassStringArray[][] return_board(){
		return board;
	}
	
	public ClassCharacterPlayer get_player_object(){
		return player;
	}
	public Point get_player_location(){
		return player.get_location();
	}
	public ClassPlaceObjects get_place_objects(){
		return objects;
	}
	public boolean has_current_animations(){
		return (animations.size() > 0) || animation_residue || (animation_text.size() > 0);
	}
	public CopyOnWriteArrayList<ClassAnimationIterator> get_animations(){
		return animations;
	}
	public CopyOnWriteArrayList<ClassAnimationString> get_text_animations(){
		return animation_text;
	}
}
